import os
import re
from pathlib import Path
from typing import List, Dict, Set
from config import JavaBugDetectorConfig

class JavaFileScanner:
    def __init__(self, project_path: str):
        self.project_path = Path(project_path)
        self.config = JavaBugDetectorConfig()
    
    def _should_ignore_dir(self, dir_path: Path) -> bool:
        """检查是否应该忽略目录"""
        dir_name = dir_path.name
        return (
            dir_name in self.config.IGNORE_DIRS or
            dir_name.startswith('.') and dir_name != '.'
        )
    
    def _should_ignore_file(self, file_path: Path) -> bool:
        """检查是否应该忽略文件"""
        file_name = file_path.name
        file_ext = file_path.suffix.lower()
        
        # 只处理Java文件
        if file_ext not in self.config.JAVA_EXTENSIONS:
            return True
        
        # 检查文件名
        if file_name in self.config.IGNORE_FILES:
            return True
        
        # 检查文件大小
        try:
            if file_path.stat().st_size > self.config.MAX_FILE_SIZE:
                return True
        except OSError:
            return True
        
        return False
    
    def scan_java_files(self) -> List[Dict[str, any]]:
        """扫描项目中的所有Java文件"""
        java_files = []
        
        for root, dirs, filenames in os.walk(self.project_path):
            root_path = Path(root)
            
            # 过滤需要忽略的目录
            dirs[:] = [d for d in dirs if not self._should_ignore_dir(root_path / d)]
            
            for filename in filenames:
                file_path = root_path / filename
                
                if not self._should_ignore_file(file_path):
                    relative_path = file_path.relative_to(self.project_path)
                    
                    java_files.append({
                        'path': str(file_path),
                        'relative_path': str(relative_path),
                        'name': filename,
                        'size': file_path.stat().st_size,
                        'package': self._extract_package_name(file_path)
                    })
        
        return java_files
    
    def _extract_package_name(self, file_path: Path) -> str:
        """从Java文件中提取包名"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read(1000)  # 只读前1000字符查找package声明
                package_match = re.search(r'package\s+([a-zA-Z_][a-zA-Z0-9_.]*)\s*;', content)
                return package_match.group(1) if package_match else "default"
        except:
            return "unknown"
    
    def get_file_content(self, file_path: str) -> str:
        """获取Java文件内容"""
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                return f.read()
        except UnicodeDecodeError:
            # 尝试其他编码
            encodings = ['gbk', 'latin1', 'ascii']
            for encoding in encodings:
                try:
                    with open(file_path, 'r', encoding=encoding) as f:
                        return f.read()
                except UnicodeDecodeError:
                    continue
            raise Exception(f"无法读取文件 {file_path}，编码不支持")
        except Exception as e:
            raise Exception(f"读取文件 {file_path} 时出错: {str(e)}")
    
    def quick_bug_scan(self, content: str) -> Dict[str, int]:
        """快速预扫描，识别潜在的BUG模式"""
        bug_indicators = {}
        
        for i, pattern in enumerate(self.config.COMMON_BUG_PATTERNS):
            matches = re.findall(pattern, content, re.IGNORECASE | re.MULTILINE)
            if matches:
                pattern_names = [
                    "可能的空指针风险", "空字符串初始化", "资源未关闭风险", 
                    "数据库连接风险", "空异常处理", "异常打印到控制台",
                    "非线程安全的静态变量", "同步代码块", "SQL注入风险", "数组操作风险"
                ]
                if i < len(pattern_names):
                    bug_indicators[pattern_names[i]] = len(matches)
        
        return bug_indicators
